using RaceHFTools.BluetoothLE.Bean;
using RaceHFTools.BluetoothLE.Bean.Module;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using System.Text;

namespace RaceHFTools.Pages
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class InfoPage : ContentPage
    {
        private readonly Bean bean;

        public InfoPage(Bean bean)
        {
            InitializeComponent();

            this.bean = bean;
        }

        #region OnAppearing/OnDisappearing
        protected override void OnAppearing()
        {
            base.OnAppearing();

            if (bean.IsConnect)
            {
                Task.Run(async () =>
                {
                    await bean.Info.StartListening();

                    bean.Tweak.DeviceGetIdEvent += OnIdGet;
                    bean.Tweak.DeviceGetLastPowerTimeEvent += OnUtcGet;
                    bean.Tweak.DeviceGetHwVersionEvent += OnHwVersionGet;
                    bean.Tweak.DeviceGetHwBatchEvent += OnHwBatchGet;
                    bean.Tweak.DeviceGetFwVersionEvent += OnFwVersionGet;
                    bean.Tweak.DeviceGetFwNumberEvent += OnFwVersionGet;
                    bean.Tweak.DeviceGetBlVersionEvent += OnBlVersionGet;
                    await bean.Tweak.GetDeviceAll();

                    await Task.Delay(200);
                    bean.Info.InfoGetBatteryEvent += OnBatteryGet;
                    bean.Info.InfoGetUsbEvent += OnUsbGet;
                    bean.Info.InfoGetSdcardEvent += OnSdcardGet;
                    bean.Info.OnGnssChanged += OnGnssGet;
                    bean.Info.OnGsensorChanged += OnGsensorGet;
                    bean.Info.OnDebugChanged += OnDebugGet;
                    await bean.Info.GetInfoAll();
                });
            }
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();

            bean.Tweak.DeviceGetIdEvent -= OnIdGet;
            bean.Tweak.DeviceGetLastPowerTimeEvent -= OnUtcGet;
            bean.Tweak.DeviceGetHwVersionEvent -= OnHwVersionGet;
            bean.Tweak.DeviceGetHwBatchEvent -= OnHwBatchGet;
            bean.Tweak.DeviceGetFwVersionEvent -= OnFwVersionGet;
            bean.Tweak.DeviceGetFwNumberEvent -= OnFwVersionGet;
            bean.Tweak.DeviceGetBlVersionEvent -= OnBlVersionGet;

            bean.Info.InfoGetBatteryEvent -= OnBatteryGet;
            bean.Info.InfoGetUsbEvent -= OnUsbGet;
            bean.Info.InfoGetSdcardEvent -= OnSdcardGet;
            bean.Info.OnGnssChanged -= OnGnssGet;
            bean.Info.OnGsensorChanged -= OnGsensorGet;
            bean.Info.OnDebugChanged -= OnDebugGet;
        }
        #endregion

        #region 回调接口
        void OnIdGet(byte[] id)
        {
            bean.Id = id;
            StringBuilder sb = new StringBuilder();
            foreach (byte x in id)
                sb.Append($"{x:X2}");
            Device.BeginInvokeOnMainThread(() => lblDeviceId.Text = sb.ToString());
        }

        void OnUtcGet(uint utc)
        {
            bean.LastPowerUtc = utc;
        }

        void OnHwVersionGet(string version)
        {
            bean.HardwareVersion = version.Split(new char[] { '\0' })[0];
            if (!string.IsNullOrWhiteSpace(bean.HardwareVersion) && !string.IsNullOrWhiteSpace(bean.HardwareBatch))
                Device.BeginInvokeOnMainThread(() => lblDeviceHardwareVersion.Text = $"{bean.HardwareVersion}({bean.HardwareBatch})");
        }

        void OnHwBatchGet(string batch)
        {
            bean.HardwareBatch = batch.Split(new char[] { '\0' })[0];
            if (!string.IsNullOrWhiteSpace(bean.HardwareVersion) && !string.IsNullOrWhiteSpace(bean.HardwareBatch))
                Device.BeginInvokeOnMainThread(() => lblDeviceHardwareVersion.Text = $"{bean.HardwareVersion}({bean.HardwareBatch})");
        }

        void OnFwVersionGet(string version)
        {
            bean.FirmwareVersion = version.Split(new char[] { '\0' })[0];
            if (!string.IsNullOrWhiteSpace(bean.FirmwareVersion) && !string.IsNullOrWhiteSpace(bean.FirmwareNumber))
                Device.BeginInvokeOnMainThread(() => lblDeviceFirmwareVersion.Text = $"{bean.FirmwareVersion}({bean.FirmwareNumber})");
        }

        void OnFwVersionGet(uint num)
        {
            bean.FirmwareNumber = num.ToString();
            if (!string.IsNullOrWhiteSpace(bean.FirmwareVersion) && !string.IsNullOrWhiteSpace(bean.FirmwareNumber))
                Device.BeginInvokeOnMainThread(() => lblDeviceFirmwareVersion.Text = $"{bean.FirmwareVersion}({bean.FirmwareNumber})");
        }

        void OnBlVersionGet(string version)
        {
            bean.BootloaderVersion = version;
            Device.BeginInvokeOnMainThread(() => lblDeviceBootloaderVersion.Text = $"{bean.BootloaderVersion}");
        }

        void OnGnssGet(Info.Gnss gnss)
        {
            DateTime dt = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1970, 1, 1), TimeZoneInfo.Local);
            dt = dt.AddSeconds(gnss.Seconds);
            Device.BeginInvokeOnMainThread(() =>
            {
                lblGnssTime.Text = dt.ToString() + "(" + gnss.MilliSeconds.ToString("D3") + ")";
                lblGnssLongtitude.Text = gnss.Longitude.ToString("F6");
                lblGnssLatitude.Text = gnss.Latitude.ToString("F6");
                lblGnssHeight.Text = gnss.Height.ToString();
                lblGnssSpeed.Text = gnss.Speed.ToString("F2") + "(" + ((int)gnss.Direction).ToString() + ")";
                lblGnssSatellites.Text = gnss.Satellites.ToString() + "(" + gnss.HDOP.ToString("F2") + ")";
                lblGnssGpsNum.Text = gnss.GpsSats.ToString();
                lblGnssGlonassNum.Text = gnss.GlonassSats.ToString();
                lblGnssGalileoNum.Text = gnss.GalileoSats.ToString();
                lblGnssBeidouNum.Text = gnss.BeidouSats.ToString();
            });
        }

        void OnGsensorGet(Info.Gsensor gsensor)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                lblGsensorX.Text = (gsensor.X >= 0 ? "+" : "") + gsensor.X.ToString("F2");
                lblGsensorY.Text = (gsensor.Y >= 0 ? "+" : "") + gsensor.Y.ToString("F2");
                lblGsensorZ.Text = (gsensor.Z >= 0 ? "+" : "") + gsensor.Z.ToString("F2");
            });
        }

        void OnDebugGet(byte[] debug)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                StringBuilder sb = new StringBuilder();
                foreach (byte x in debug)
                    sb.Append($"{x:X2} ");
                Device.BeginInvokeOnMainThread(() => lblDebug.Text = sb.ToString());
            });
        }

        void OnBatteryGet(uint batter)
        {
            Device.BeginInvokeOnMainThread(() => lblDeviceBattery.Text = batter.ToString());
        }

        void OnUsbGet(bool usb)
        {
            Device.BeginInvokeOnMainThread(() => lblDeviceUSB.TextColor = usb ? Color.Green : Color.Red);
        }

        void OnSdcardGet(bool sdcard)
        {
            Device.BeginInvokeOnMainThread(() => lblDeviceSD.TextColor = sdcard ? Color.Green : Color.Red);
        }
        #endregion

        #region 交互事件
        void ToolBarItem_Disconnect_Clicked(object sender, EventArgs e)
        {
            _ = bean.Disconnect();
        }

        void ToolBarItem_PowerOff_Clicked(object sender, EventArgs e)
        {
            _ = bean.Tweak.SetDevicePower(TweakDevicePowerMode.PowerOff);
        }

        void Button_GoFsync_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                await bean.Info.StopListening();
                await Navigation.PushAsync(new FsyncPage(bean));
            });
        }

        void Button_GoUpgrade_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                await bean.Info.StopListening();
                await Navigation.PushAsync(new UpgradePage(bean));
            });
        }

        void Button_TweakDevice_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                await bean.Info.StopListening();
                await Navigation.PushAsync(new TweakPage(bean));
            });
        }

        void Button_ManuTest_Clicked(object sender, EventArgs e)
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                await bean.Info.StopListening();
                await Navigation.PushAsync(new ManuTestPage(bean));
            });
        }
        #endregion
    }
}
